Skip to content

chore: Update yarn to 4.13, add package age gate, fix pnpm linker path detection#198

Open
dividedmind wants to merge 4 commits intomainfrom
chore/update-yarn
Open

chore: Update yarn to 4.13, add package age gate, fix pnpm linker path detection#198
dividedmind wants to merge 4 commits intomainfrom
chore/update-yarn

Conversation

@dividedmind
Copy link
Copy Markdown
Collaborator

Updates yarn from 3.6.3 to 4.13.0 and adds a 2-day minimum package age gate (npmMinimalAgeGate) as a supply-chain security measure.

Doing this unearthed some issues which were fixed:

  • Fixed hook detection for the yarn 4 pnpm linker: yarn 4 renamed the .store subdirectory from the package name to the generic package/, breaking path-based hook detection in the mocha, jest, and vitest hooks. Added matchesPackageFile() utility to handle all layouts (classic node_modules, yarn 3 pnpm, yarn 4 pnpm).
  • Switched the main project from nodeLinker: pnpm to nodeLinker: node-modules (avoids the yarn 4 pnpm linker compatibility gap with Next.js 14), and added a minimal independent test/pnpm-compat/ sub-project to keep explicit test coverage of the pnpm linker path format.

@dividedmind dividedmind self-assigned this Mar 25, 2026
@dividedmind dividedmind marked this pull request as ready for review March 25, 2026 18:05
Copilot AI review requested due to automatic review settings March 25, 2026 18:05
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Mar 25, 2026

Open in StackBlitz

npm i https://pkg.pr.new/appmap-node@198

commit: 8b6bd33

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the repo’s Yarn tooling to v4.13.0, adds a supply-chain “package age gate”, and fixes test-framework hook detection under Yarn 4’s pnpm linker layout by introducing a shared path-matching helper and exercising it via a new pnpm-compat integration test.

Changes:

  • Bump Yarn to 4.13.0, switch root nodeLinker to node-modules, and enable npmMinimalAgeGate.
  • Add matchesPackageFile() and update Vitest/Jest/Mocha hooks to support Yarn 4 pnpm linker .store/.../package/... paths.
  • Add a standalone test/pnpm-compat/ project + integration test and CI cache entries to validate pnpm-linker compatibility.

Reviewed changes

Copilot reviewed 22 out of 26 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
.yarnrc.yml Updates Yarn settings (compression, node linker, minimal age gate, yarnPath).
package.json Updates packageManager to Yarn 4.13.0.
.github/workflows/ci.yml Adds caching for test/pnpm-compat Yarn cache/global folders.
src/util/matchesPackageFile.ts New helper to match hook target files across node_modules layouts.
src/transform.ts Re-exports matchesPackageFile (and keeps hook dispatch unchanged).
src/hooks/vitest.ts Switches Vitest hook target detection to matchesPackageFile().
src/hooks/jest.ts Switches Jest hook target detection to matchesPackageFile().
src/hooks/mocha.ts Switches Mocha hook target detection to matchesPackageFile().
test/pnpm-compat.test.ts New integration test running Vitest under Yarn pnpm linker.
test/pnpm-compat/appmap.yml New AppMap config for pnpm-compat fixture project.
test/pnpm-compat/package.json New fixture package manifest (Vitest dependency).
test/pnpm-compat/vitest.config.mjs Minimal Vitest config for pnpm-compat fixture.
test/pnpm-compat/sum.test.js Minimal Vitest test used by pnpm-compat fixture.
test/pnpm-compat/.yarnrc.yml Yarn config for pnpm-compat fixture (pnpm linker + local cache folders).
test/pnpm-compat/.gitignore Ignores .yarn/ within pnpm-compat fixture.
test/pnpm-compat/yarn.lock Lockfile for pnpm-compat fixture project.
test/vitest1/appmap.yml Excludes node_modules from the vitest package path.
test/vitest2/appmap.yml Excludes node_modules from the vitest package path.
test/vitest3/appmap.yml Excludes node_modules from the vitest package path.
test/vitest4/appmap.yml Excludes node_modules from the vitest package path.
test/next.test.ts Uses require.resolve to locate Next’s bin in the fixture project.
test/next16.test.ts Uses require.resolve to locate Next’s bin in the fixture project.
test/__snapshots__/next16.test.ts.snap Updates snapshot to match new Next.js output/header values.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

dividedmind and others added 3 commits March 30, 2026 06:03
Yarn 4 pnpm linker changed the .store subdirectory naming from the
package name (e.g. .store/mocha-npm-10.8.2-hash/mocha/) to a generic
'package/' directory (.store/mocha-npm-10.8.2-hash/package/). This
broke all endsWith() path checks in the mocha, jest, and vitest hooks,
which relied on resolved paths ending with /mocha/lib/runner.js etc.

Add matchesPackageFile() utility that handles both the classic
node_modules layout and the yarn 4 pnpm linker store layout, and
update all three hooks to use it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…-project

Yarn 4 changed the pnpm linker's .store subdirectory name to 'package/'
(was the package name in yarn 3), breaking path-based hook detection.

Switch the main project to nodeLinker: node-modules to avoid the issue,
and add test/pnpm-compat/ as a minimal independent yarn sub-project with
nodeLinker: pnpm to specifically test the pnpm linker path format support.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…kiness

The "mapping a script using async tracking timeout 10" test was flaky on
Node.js 18: instead of the expected timeout=10 event ordering it produced
the timeout=0 ordering, as if async tracking buffering had never engaged.
The test passes on Node.js 20, 22, and 24.

Hypothesis: timers/promises.setTimeout creates an internal Timeout async
resource that overrides the AsyncLocalStorage context on Node.js 18 when
the timer fires, causing Recording.buffer to fall back to rootBuffer.
Since rootBuffer was ≥10ms old at that point, passEventsAndClearBuffer
flushed all buffered events before getMessage reached the stream. Using
`new Promise(resolve => globalThis.setTimeout(resolve, 100))` avoids the
internal Timeout resource — the Promise is created inside asyncStorage.run
so its continuation should inherit the correct context on all Node versions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants